#include <msp430x26x.h>
#include <stdio.h>
#include "Gumstix.h"

/******************************************************
 * CONSTANT DEFINES - define private constants for use in this module
 ******************************************************/
#define TX_BUFFER_SIZE (sizeof(SensorInfo))
#define RX_BUFFER_SIZE (60)
/******************************************************/

/******************************************************
 * INTERRUPT DECLARES - declare ISRs and link their handlers
 ******************************************************/
__interrupt void usart0RX(void);  // UART RX interrupt
__interrupt void usart0TX(void);  // UART TX interrupt
/******************************************************/

/******************************************************
Variable Declarations, initializations 
******************************************************/
static GumstixInputBuffer OutBuffer;	//declare the RX buffer object to be used
static GumstixOutputBuffer InBuffer;	//declare the TX buffer object to be used
static unsigned char tx_buffer_ptr;		//index into the transmit buffer (next spot)
/*****************************************************/

/******************************************************
Private functions
******************************************************/
static void gumstix_tx_byte_to_slave(char Byte);
/*****************************************************/

/**************************************************
Initialize Gumstix communication
**************************************************/
void GumstixInit(void)
{
	int i; // Index variable
	
	//configure UCA0 (for Gumstix Linux board communication)
  	UCA0CTL0 = 0;						// 8N1 UART config
  	UCA0CTL1 |= (UCSSEL_2+UCSWRST);     // SMCLK source and hold UART in reset
  	UCA0BR0 = 4;                    	// see tables in user guide (115200)
  	UCA0BR1 = 0;                    	// 
  	UCA0MCTL = (UCBRS2+UCBRS0+			// UCBRS = 5
  			    UCBRF1+UCBRF0+			// UCBRF = 3
  			    UCOS16);      			// oversampling mode
  	UCA0CTL1 &= ~UCSWRST;             	// **Initialize USCI state machine**
  	UC0IE |= UCA0RXIE;                  // Enable USCI_A1 RX interrupt
    
 	// Initialize the RX & TX buffer structures.  
	for(i = 0; i < RX_BUFFER_SIZE; i++)
	{
		InBuffer.buffer[i]=0;
	}
	for(i = 0; i < TX_BUFFER_SIZE; i++)
	{
		OutBuffer.buffer[i]=0;
	}
	InBuffer.start = &InBuffer.buffer[0]; 	//get the address of the buffer head
	InBuffer.end = &InBuffer.buffer[0];  	//get the address of the buffer tail
	InBuffer.length = 0;					//initialize the buffer length to 0
	OutBuffer.start = &OutBuffer.buffer[0]; //get the address of the buffer head
	OutBuffer.end = &OutBuffer.buffer[0];  	//get the address of the buffer tail
	OutBuffer.length = 0;					//initialize the buffer length to 0
	tx_buffer_ptr = 0;						//initialize the tx pointer to 0
}
/*************************************************/

/**************************************************
Send runtime info to the Gumstix computer.
**************************************************/
void GumstixTXInfo(SensorInfo *data)
{
	unsigned char i;
	unsigned char *c;
	
	// Convert the sensor info pointer to byte pointer so we can send each byte individually
	c = (unsigned char*)data;
	
	for (i = 0; i < sizeof(SensorInfo); i++)
	{
		gumstix_tx_byte_to_slave(c[i]);
	}
}
/*************************************************/

/**************************************************
Return whether we have heard from the Gumstix (1 for true, 0 for false)
**************************************************/
unsigned char GumstixIsReady(void)
{
	if (InBuffer.length == 1)
	{
		// reset the buffer
		InBuffer.length = 0;
		
		return (InBuffer.buffer[0] == 'a');
	}
	
	return 0;
}
/*************************************************/

/**************************************************
Send a sync character to the Gumstix
**************************************************/
void GumstixSendSync(void)
{
	gumstix_tx_byte_to_slave('b');
}
/*************************************************/

/**************************************************
Receive the sync character from the Gumstix
**************************************************/
unsigned char GumstixRxSync(void)
{
	if (InBuffer.length == 1)
	{
		InBuffer.length = 0;
		
		return (InBuffer.buffer[0] == 'c');
	}
	
	return 0;
}
/*************************************************/

/**************************************************
tx_byte_to_slave - fn sends a single byte using UART0
**************************************************/
static void gumstix_tx_byte_to_slave(char Byte)
{
  	// Check TX buffer is not full before trying to add more data (drop overflow)
	if(OutBuffer.length < TX_BUFFER_SIZE)
	{
		OutBuffer.buffer[OutBuffer.length] = Byte;	// Place data in buffer
		OutBuffer.length++;							// increment buffer length
		UC0IE |= UCA0TXIE;							// Enable the USCI_A1 TX interrupt
	}
}
/*************************************************/

/********************************************************
ISR: usart0_rx - this code gets executed when USART1 receives a byte
********************************************************/
#pragma vector=USCIAB0RX_VECTOR
__interrupt void usart0RX(void)
{
	// If the RX buffer is not full, copy RXed byte into it
	if(InBuffer.length < TX_BUFFER_SIZE)
	{
		InBuffer.buffer[InBuffer.length] = UCA0RXBUF;	// Copy Data
		InBuffer.length++;								// increment buffer length
	}
	else
	{
		InBuffer.length = 0;  // reset buffer if we would have written past the end
	}  
}
/*******************************************************/

/********************************************************
ISR: usart0_tx - this code gets executed when USART1 TX buffer is empty
********************************************************/
#pragma vector=USCIAB0TX_VECTOR
__interrupt void usart0TX(void)
{
	// If there are still bytes to be sent send a byte
	if (tx_buffer_ptr < OutBuffer.length)
	{
		UCA0TXBUF = OutBuffer.buffer[tx_buffer_ptr++];
	}
	else
	{
		// We have flushed the buffer, clear the buffer, reset the TX data pointer
		tx_buffer_ptr = 0;
		OutBuffer.length = 0;
		
		// Also clear the interrupt enable so we don't have useless interrupts
		UC0IE &= ~UCA0TXIE;
	}
}
